﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using RealtReview.DataAccess.Entities;
using RealtReview.DataAccess.Interfaces;
using RealtReview.DataAccess.SearchParameters;
using RealtyReview.Business.Helpers;
using RealtyReview.Business.Interfaces;
using RealtyReview.Business.Mappings;
using RealtyReview.Business.Models.Review;
using RealtyReview.Business.Models.ViewModels;

namespace RealtyReview.Business.Services
{
    public class ReviewsService : IReviewsService
    {
        private IReviewRepository reviewRepository;
        private IAddressRepository addressRepository;
        private IApartmentRepository apartmentRepository;
        private DbContext dbContext;

        public ReviewsService(IReviewRepository reviewRepository,
            IAddressRepository addressRepository,
            IApartmentRepository apartmentRepository,
            DbContext realtReviewContext)
        {
            this.reviewRepository = reviewRepository;
            this.addressRepository = addressRepository;
            this.apartmentRepository = apartmentRepository;
            this.dbContext = realtReviewContext;
        }


        public Guid AddReview(Guid? userId, ReviewDetailsViewModel model)
        {
            using (var transaction = dbContext.Database.BeginTransaction())
            {
                var address = addressRepository.InsertOrUpdate(model.AddressViewModel.ToAddress());
                reviewRepository.SaveChanges();
                var apartment = apartmentRepository.InsertOrUpdate(model.ApartmentViewModel.ToApartment());
                apartment.AdressId = address.Id;
                apartmentRepository.SaveChanges();
                model.ReviewViewModel.Status = ReviewStatus.AwaitingApproval;
                var review = reviewRepository.InsertOrUpdate(model.ReviewViewModel.ToReview());
                review.UserId = userId;
                review.ApartmentId = apartment.Id;
                reviewRepository.SaveChanges();
                transaction.Commit();
                return review.Id;
            }
        }

        public bool EditReview(Guid userId, ReviewDetailsViewModel model)
        {
            throw new NotImplementedException();
        }

        public bool RevokeReview(Guid userId, Guid reviewId)
        {
            throw new NotImplementedException();
        }

        public IEnumerable<ReviewListViewModel> GetReviews(ReviewSearchParameters searchParameters)
        {
            var reviews = reviewRepository.Search(searchParameters);
            return reviews.Select(x =>
            {
                var json = Serializer.ToObject<ReviewViewModel>(x.OptionalParameters);
                return new ReviewListViewModel
                {
                    Description = (json != null) ? json.Description : null,
                    Latitude = x.Apartment.Address.Latitude,
                    Longitude = x.Apartment.Address.Longitude,
                    Id = x.Id,
                    Price = x.Price,
                    Status = x.Status
                };
            });
        }

        public ReviewDetailsViewModel GetReviewDetails(Guid reviewId)
        {
            var review = reviewRepository.Get(reviewId);
            return new ReviewDetailsViewModel
            {
                AddressViewModel = review.Apartment.Address.ToAddressViewModel(),
                ApartmentViewModel = review.Apartment.ToApartmentViewModel(),
                ReviewViewModel = review.ToReviewViewModel()
            };
        }
    }
}
